package recorder

import (
	"context"
	"fmt"
	"hotgo/internal/consts"
	"hotgo/internal/controller/api/recorder"
	"hotgo/internal/dao"
	"hotgo/internal/library/queue"
	"hotgo/utility/file"
	"hotgo/utility/xvideo"

	"github.com/gogf/gf/v2/database/gdb"

	"github.com/gogf/gf/v2/frame/g"
	"golang.org/x/sync/errgroup"
)

// Ocr -- @# 根据活动ID找到所有的录制文件
func (r *sRecorder) Ocr(ctx context.Context, aid int) error {
	// --  @# 组合检查录制视频文件是否存在
	var recorderFiles = make([]string, 0, 8)
	rf := g.Cfg().MustGet(ctx, "recorder.flv_dir", "/var/www/html/flv_db/")
	for i := range 8 {
		theFlvFile := fmt.Sprintf("%s%d_%d.flv", rf, aid, i+1)
		if file.FileIsExists(theFlvFile) {
			recorderFiles = append(recorderFiles, theFlvFile)
		}
	}
	// --  @# TODO：查询活动信息并透传到后续的协程中执行
	// --  @# 开始执行录制文件抽帧OCR操作
	go r.run(ctx, aid, recorderFiles)

	return nil
}

// --  @# 循环处理所有的文件，处理完成后计算总处理量，以便定时任务判断OCR是否完成
func (r *sRecorder) run(ctx context.Context, aid int, files []string) {
	var eg errgroup.Group

	for idx, innerFile := range files {
		theFile := innerFile
		eg.Go(r.fileOcr(ctx, aid, idx+1, theFile))
	}

	if err := eg.Wait(); err != nil {
		g.Log().Errorf(ctx, "录制文件抽帧图片OCR进队列出错:%v", err)
	}

	// --  @# OCR入队列完成，更新状态为入队列完成
	_, err := dao.RecordActivity.Ctx(ctx).Where(dao.RecordActivity.Columns().ActivityId, aid).Data(g.Map{
		dao.RecordActivity.Columns().OcrEnd:  1,
		dao.RecordActivity.Columns().OcrNums: gdb.Raw("`ocr_1_nums` + `ocr_2_nums` + `ocr_3_nums` + `ocr_4_nums` + `ocr_5_nums` + `ocr_6_nums` + `ocr_7_nums` + `ocr_8_nums`"),
	}).Update()
	if nil != err {
		g.Log().Errorf(ctx, "入队列OCR完成状态更新操作入库失败:%v", err)
	}
}

// --  @# 处理单个文件的抽帧OCR
func (r *sRecorder) fileOcr(ctx context.Context, aid int, cid int, file string) func() error {
	frameInterval := g.Cfg().MustGet(ctx, "recorder.frame_interval", 10).Int()
	frameDestDir := g.Cfg().MustGet(ctx, "recorder.frame_dir", "/var/www/html/frame_db/").String()
	return func() error {
		frameCount, err := xvideo.GetVideoFrameCount(file)
		if nil != err {
			return err
		}
		var i uint64
		var count uint64 = 0
		for i = 0; i < frameCount; i += uint64(frameInterval) {
			frameFile, err := xvideo.ReadFrameAsJpeg(file, i, aid, cid, frameDestDir)
			if nil != err {
				return err
			}
			g.Log().Info(ctx, "录制文件抽帧图片完成", frameFile, "第", i, "帧")
			// --  @# 发送到OCR rocketmq队列
			errQueue := queue.Push(consts.QueueRecorderOcrTopic, recorder.QueueRecorder{
				Path:       frameFile,
				Frame:      i,
				ActivityId: aid,
				CameraId:   cid,
				Regexp:     `[A-Z][0-9]{5}`,
			})
			if nil != errQueue {
				g.Log().Warningf(ctx, "录制文件抽帧图片OCR进队列出错:%v", errQueue)
				continue
			}
			count++
		}
		// --  @# 更新每个摄像头抽帧数量
		err = r.calculateCameraFrameCount(ctx, aid, cid, count)
		return err
	}
}

// --  @# 更新每个摄像头抽帧数量
func (r *sRecorder) calculateCameraFrameCount(ctx context.Context, aid int, cid int, count uint64) error {
	updateColumn := dao.RecordActivity.Columns().Ocr1Nums
	switch cid {
	case 2:
		updateColumn = dao.RecordActivity.Columns().Ocr2Nums
	case 3:
		updateColumn = dao.RecordActivity.Columns().Ocr3Nums
	case 4:
		updateColumn = dao.RecordActivity.Columns().Ocr4Nums
	case 5:
		updateColumn = dao.RecordActivity.Columns().Ocr5Nums
	case 6:
		updateColumn = dao.RecordActivity.Columns().Ocr6Nums
	case 7:
		updateColumn = dao.RecordActivity.Columns().Ocr7Nums
	case 8:
		updateColumn = dao.RecordActivity.Columns().Ocr8Nums
	default:
		updateColumn = dao.RecordActivity.Columns().Ocr1Nums
	}
	_, err := dao.RecordActivity.Ctx(ctx).Where(dao.RecordActivity.Columns().ActivityId, aid).Data(g.Map{
		updateColumn: count,
	}).Update()
	return err
}
